/*******************************************************************************
*  file    : solutions.hpp
*  created : 15.07.2014
*  author  : Slyshyk Oleksiy (alexSlyshyk@gmail.com)
*******************************************************************************/

#ifndef SOLUTIONS_HPP
#define SOLUTIONS_HPP

#include <QObject>
#include <QMap>
#include <QQueue>
#include <QVector>
#include <QVariantMap>
#include <QFutureWatcher>
#include <QSharedPointer>
#include <QMutex>
#include <utility>

#ifndef Q_MOC_RUN
#include <boost/circular_buffer.hpp>
#endif

#include "dataprovider.hpp"

class TransformNamedData;
class TransformNamedIntData;
class QTimer;

struct DataObjectSolution
{
    DataObjectSolution() :
        delta_t_signal_L(-1000.0),delta_t_signal_R(-1000.0),
        delta_t_pulse_L (-1000.0),delta_t_pulse_R (-1000.0) {}
    double delta_t_signal_L;
    double delta_t_signal_R;
    double delta_t_pulse_L;
    double delta_t_pulse_R;

    double delta_V_L = -1000.0;
    double delta_V_R = -1000.0;
    double delta_V   = -1000.0;

    double temperature = -1000.0;
    double pressure    = -1000.0;
    qint64 time        = -10;
};

typedef std::pair<int, NamedDataPtr>                      QuieuePair;
typedef boost::circular_buffer<DataObjectSolution>        DataSolutionBuffer;
typedef boost::circular_buffer<std::pair<qint64,double>>  FilteredWindSpeedBuffer;

class Solutions : public QObject
{
    Q_OBJECT
public:
    Solutions(QObject* parent = 0);
    ~Solutions();
    QStringList patternList       () const;
    QStringList transformationList() const;
    void setParams(const QVariantMap &pulse, const QVariantMap& signal);

    const DataSolutionBuffer&      solutions () const;
    const FilteredWindSpeedBuffer& speeds    () const;
    const FilteredWindSpeedBuffer& ma_speeds () const;
    const FilteredWindSpeedBuffer& ma2_speeds() const;

    double temperature() const;
    void   setTemperature(double value);
    void   setTransformPlugins   (const QSharedPointer<QMap<QString, TransformNamedData*>>&    plugins);
    void   setTransformIntPlugins(const QSharedPointer<QMap<QString, TransformNamedIntData*>>& plugins);
    void   setTaskSize(int ts);

public slots:
    void onDataReady(int, NamedDataPtr);
    void onDataObjectReady(DataObjectPtr);
    void setResponceTime(double t_l, double t_r);
    void flushData();
private:
    DataObjectSolution calculateDataObject(DataObjectPtr, QVariantMap param_signal, QVariantMap param_transmit);
    DataObjectSolution calcData(const NamedData*    datL, const NamedData*    datR,
                                QVariantMap param_signal, QVariantMap param_pulse);
    DataObjectSolution calcData(const NamedIntData* datL, const NamedIntData* datR,
                                QVariantMap param_signal, QVariantMap param_pulse);
private slots:
    void startTransform(int id, NamedDataPtr data_ptr);
    void startTransform(DataObjectPtr);
    void computationFinished();
    void computationDataObjectFinished();
    void saveReport();
signals:
    void windSpeedChanged(qint64 t, double s);
    void taskDone(); // должен высылаться после обработки определенного количества данных
private:
    QSharedPointer<QMap<QString, TransformNamedData*>> transformPlugins_;
    QSharedPointer<QMap<QString, TransformNamedIntData*>>   transformIntPlugins_  ;
private:
    int    task_size_  = 0;
    int    task_count_ = 0;

    double last_calc_len_L        = 0.;
    double last_calc_len_R        = 0.;
    double base_time_L_           = 0.0 ;     // время прохождения волны между датчиками.
    double base_time_R_           = 0.0 ;     // время прохождения волны между датчиками.
    double base_temp_             = 273.15;   // температура (в Кельвинах) во время эталонного замера.
    double last_calc_pulse_time_L = 0.;
    double last_calc_time_L       = 0.;
    double last_calc_pulse_time_R = 0.;
    double last_calc_time_R       = 0.;
    QMutex last_calk_mutex_;

    QVector<std::pair<int, double>> pulse_t_;
    QVector<std::pair<int, double>> signal_t_;

    QVariantMap par_pulse_;
    QVariantMap par_signal_;

    QVector<double>                wind_speeds_     ;
    boost::circular_buffer<double> speeds_for_ma_   ;
    boost::circular_buffer<double> speeds_for_ma2_  ;
    DataSolutionBuffer             data_solutions_  ;
    FilteredWindSpeedBuffer        speeds_          ;
    FilteredWindSpeedBuffer        ma_speeds_       ;
    FilteredWindSpeedBuffer        ma2_speeds_      ;


    QList<QFutureWatcher<NamedData*>*>          futureWatcherList_;
    QList<QFutureWatcher<DataObjectSolution> *> futureWatcherDataObjectList_;

    //QQueue<DataObjectPtr> data_object_queue_;
    QQueue<QuieuePair>    dataQueue_;

    QTimer* report_timer_;
    QVector<QStringList*> report_;
};

#endif // SOLUTIONS_HPP
